import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter_base/model/base_model.dart';

import 'api_service.dart';

class DioUtil {
  // 单例公开访问点
  factory DioUtil() => _getInstance()!;

  // 私有构造函数
  DioUtil._() {
    // 具体初始化代码
    //BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    final BaseOptions options = BaseOptions(
      baseUrl: ApiService.BASE_URL,
      connectTimeout: 10000,
      receiveTimeout: 5000,
      //Http请求头.
      headers: {'Authorization': 'Bearer '},
      //请求的Content-Type，默认值是"application/json; charset=utf-8",Headers.formUrlEncodedContentType会自动编码请求体.
      contentType: Headers.formUrlEncodedContentType,
      //表示期望以那种格式(方式)接受响应数据。接受四种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
      responseType: ResponseType.plain,
    );

    dio = Dio(options);
    dio.interceptors.add(InterceptorWrap());
  }

  // 静态私有成员，没有初始化
  static DioUtil? _instance;

  // 静态、同步、私有访问点
  static DioUtil? _getInstance() {
    _instance ??= DioUtil._();
    return _instance;
  }

  late Dio dio;

  /*
   * get请求
   */
  Future<BaseModel> get(String url,
      {Map<String, dynamic>? data, Options? options, CancelToken? cancelToken}) async {
    Response? response;
    try {
      response =
          await dio.get(url, queryParameters: data, options: options, cancelToken: cancelToken);
      // print('get success 请求路径---------$url');
      // print('get success---------${response.statusCode}');
      // print('get success---------${response.data}');
    } on DioError catch (e) {
      print('get error---------$e');
      formatError(e);
    } catch (e) {
      print('get error---------$e');
    }
    final baseModel= BaseModel.fromJson(jsonDecode(response!.data.toString()) as Map<String,dynamic>);
    return baseModel;
  }

  /*
   * post请求
   */
  Future<Response> post(String url,
      {Map<String, dynamic>? data, Options? options, CancelToken? cancelToken}) async {
    Response? response;
    try {
      response =
          await dio.post(url, queryParameters: data, options: options, cancelToken: cancelToken);
      print('post success---------${response.data}');
    } on DioError catch (e) {
      print('post error---------$e');
      formatError(e);
    }
    return response!;
  }

  /*
   * 下载文件
   */
  Future downloadFile(String urlPath, savePath) async {
    Response? response;
    try {
      response = await dio.download(urlPath, savePath, onReceiveProgress: (int count, int total) {
        //进度
        print('$count $total');
      });
      print('downloadFile success---------${response.data}');
    } on DioError catch (e) {
      print('downloadFile error---------$e');
      formatError(e);
    }
    return response?.data;
  }

  /*
   * error统一处理
   */
  void formatError(DioError e) {
    if (e.type == DioErrorType.connectTimeout) {
      // It occurs when url is opened timeout.
      print('连接超时');
    } else if (e.type == DioErrorType.sendTimeout) {
      // It occurs when url is sent timeout.
      print('请求超时');
    } else if (e.type == DioErrorType.receiveTimeout) {
      //It occurs when receiving timeout
      print('响应超时');
    } else if (e.type == DioErrorType.response) {
      // When the server response, but with a incorrect status, such as 404, 503...
      print('出现异常');
    } else if (e.type == DioErrorType.cancel) {
      // When the request is cancelled, dio will throw a error with this type.
      print('请求取消');
    } else {
      //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null.
      print('未知错误');
    }
  }

  /*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequests(CancelToken token) {
    token.cancel('cancelled');
  }
}
///拦截器
class InterceptorWrap extends InterceptorsWrapper {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    super.onRequest(options, handler);
    print('\n================== 请求数据 ==========================');
    print('url = ${options.uri.toString()}');
    print('headers = ${options.headers}');
    print('params = ${options.data}');
  }

  @override
  void onResponse(Response<dynamic> response, ResponseInterceptorHandler handler) {
    super.onResponse(response, handler);
    print('\n================== 响应数据 ==========================');
    print('code = ${response.statusCode}');
    print('data = ${response.data}');
    print('\n');
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    print('\n================== 错误响应数据 ======================');
    print('type = ${err.type}');
    print('message = ${err.message}');
    print('stackTrace = ${err.stackTrace}');
    print('\n');
  }
}
